//loader中在16位实模式下工作的代码(计算机开始时是工作在实模式下的)
__asm__(".code16gcc");  //该行定义表示后面的代码都是16位下执行的代码

#include "loader.h"

boot_info_t boot_info;

static void show_msg(char* msg){
    char c;
    while((c=*msg++) !='\0'){
        __asm__ __volatile__(
            "mov $0xe,%%ah\n\t"
            "mov %[ch],%%al\n\t"
            "int $0x10"::[ch]"r"(c)
        );
    }
}

static void detect_memory(){    //内存检测
    SMAP_entry_t smap_entry;
    show_msg("try to detect memory.....\r\n");
    int signature,bytes;
    uint32_t contID = 0;

    boot_info.ram_region_count=0;
    for (int i = 0; i < BOOT_RAM_REGION_MAX; i++)
    {
        SMAP_entry_t *entry = &smap_entry;
        __asm__ __volatile__("int  $0x15"
			: "=a"(signature), "=c"(bytes), "=b"(contID)
			: "a"(0xE820), "b"(contID), "c"(24), "d"(0x534D4150), "D"(entry));
        
        if(signature != 0x534D4150){
            show_msg("memory detect failed!");
            return;
        }

		if (bytes > 20 && (entry->ACPI & 0x0001) == 0){
			continue;
		}

        if(entry->Type == 1){//可用内存,保存到结构体中
            boot_info.ram_region_cfg[boot_info.ram_region_count].start=entry->BaseL;
            boot_info.ram_region_cfg[boot_info.ram_region_count].size=entry->LengthL;
            boot_info.ram_region_count++;
        }

        if(contID==0){  //内存读取完毕,跳出循环
            break;
        }
    }

    show_msg("memory detect complete...\r\n");
}

uint16_t gdt_table[][4]={
    {0,0,0,0},
    {0xFFFF,0x0000,0x9a00,0x00cf},
    {0xFFFF,0x0000,0x9200,0x00cf},
};

static void enter_protect_mode(){
    cli();  //关中断

    uint8_t v = inb(0x92);  //打开A20地址线
    outb(0x92,v|0x2);

    lgdt((uint32_t)gdt_table,sizeof(gdt_table));    //加载gdt表

    uint32_t cr0=read_cr0();    //设置cr0寄存器开启保护模式的标志位
    write_cr0(cr0|1);

    //跳转到32位代码
    far_jump(8,(uint32_t)protect_mode_entry);

}

void loader_entry(){
    show_msg("...........loading............\r\n");
    detect_memory();
    enter_protect_mode();

    for (;;){}
    
}